/*Timer2 generates PCLK at 256kHz.  That's the lowest permissible rate.
 *The original idea was to generate the FSYNC signal in the ISR of timer2 compare, but
 *There are only 64 processor cycles available as the ISR runs at 256kHz.  Besides, there would be 
 *hardly time left to do other useful work.
 *So the alternative is to generate the 7.8kHz FSYNC with timer1.
 *
 *For synchronizing the datashifting with the PCLK, ISR-routines are used that are triggered on the
 *rising edges of PCLK.
 *The amount of available processing cycles to shift out/in the PCM-data is quite limited.  Shifting out a bit and 
 *shifting in a bit in a single ISR-call takes too long.  So these two operations will have their own time frames.
 *First the ISR for shifting in data gets called until all data is shifted in.  After that the same ISR is used for shifting out data
 *on the bus.
 *
 *This functionality can be tested by setting direct register 8 of the SLIC to 0x02. Don't try to test with a DC-signal, because that won't work.
 *In the signal path, there's an interpolation filter, decimation filter, high-pass filters, so you'll never get the same byte back as the one you sent.
 *
 *MCU Register definitions can be found on: 
 * Linux: /usr/lib/avr/include/avr
 * Windows: ..\arduino-1.0-windows\arduino-1.0\hardware\tools\avr\avr\include\avr
 */

//#include "WProgram.h"            //contains Arduino constants (Arduino 0.22)
#include <Arduino.h>               //contains Arduino constants (Arduino 1.0)

byte yDTX=0;                       //Data generated by SLIC
byte yDRX;
byte yCycleCtr=0;
volatile boolean bDoneFlag;

void controlPcmGateway(boolean bOn){
  if(bOn){
    bitSet(TIMSK1,TOIE1);            //Enable interrupts when timer1 reaches TOP of counter.
  }
  else{
    bitClear(TIMSK1,TOIE1);
  }
}

//Send & receive bytes using PCM bus.  This function will hang until data is available to return.
//\param data    byte that will be sent to the SLIC
//\return        byte returned from SLIC
byte PCMcomm(byte data){
  while(!bDoneFlag);
  bDoneFlag=false;
  yDRX=data;
  return yDTX;
}

void setupPcmGateway(){
  //http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM

  //Setting up PCLK: 250kHz, duty cycle 50% (4 timeslots/frame)
  bitClear(PRR,PRTIM2);            //Power up Timer2
  bitSet(TCCR2B,WGM22);            //Put timer 2 in fast PWM-mode with top at OCR2A
  bitSet(TCCR2A,WGM21);
  bitSet(TCCR2A,WGM20);
  bitSet(TCCR2A, COM2B1);          //Set OC2B-pin upon compare match
  bitSet(TCCR2A, COM2B0);
  bitClear(TCCR2B, CS22);          //No prescaler, fTimer = fclk = 16MHz
  bitClear(TCCR2B, CS21);
  bitSet(TCCR2B, CS20);
  OCR2A=63;                        //In fast PWM-mode, timer will be cleared when it reaches OCR2A value.
  //So the timer frequency becomes: fclk/(N*(1+OCR2A)) = 16M/(1*(1+63))=250kHz
  OCR2B=31;                        //50% dutycycle clock on OC2B-pin.

  //Setting up FSYNC: 7.8kHz, duty cycle=1/32, synchronous rising edge with PCLK.
  bitClear(PRR,PRTIM1);            //Power up Timer1
  bitSet(TCCR1A,COM1A1);           //Clear OC1A-pin upon compare match 
  bitClear(TCCR1A,COM1A0);
  bitClear(TCCR1A,WGM11);          //Use fast PWM-mode 8bit
  bitSet(TCCR1A,WGM10);
  bitSet(TCCR1B,WGM12);
  bitClear(TCCR1B,WGM13);
  bitClear(TCCR1B,CS12);           //Set prescaler /8, so the FSYNC frequency becomes: 16MHz/8/256 = 7.8kHz
  bitSet(TCCR1B,CS11);
  bitClear(TCCR1B,CS10);
  OCR1A=7;                         //Set duty cycle to 1/32

  //Synchronizing timer1 & timer2 (using only an old HM412 scope)
  TCNT1=0;
  TCNT2=36;
}

//This time routine will be executed at a rate of 7.8KHz.
//Only every two interrupts will the other interrupt (for shifting data) be enabled.
//So data will only be sampled at 3.9KHz instead of 7.8KHz.  According to some papers, this only slightly affects voice quality (but it reduces data transfer by a factor of two).
ISR(TIMER1_OVF_vect)
{
  static boolean bTrig=false;
  if(bTrig==false)
  {
    bitSet(TIMSK2,OCIE2A);           //Enable interrupt on OCR2B compare match
    yCycleCtr=0;
    TIMSK0&=0xFE;                    //Disable interrupts on timer0 (used by Arduino internally), because it causes jitter on TIMER2-interrupts.
  }
  bTrig=~bTrig;
}

//Interrupt routine for shifting in & out data from & to SLIC
//Shifting in & out at the same time can't be done, because it takes too much time for one ISR-call.  So first
//data is shifted out, after that, data from the SLIC is shifted in.
ISR(TIMER2_COMPA_vect){
  if(yCycleCtr++!=0)
  {
    if(yCycleCtr<11)
    {
      if(yDRX & 0x80)
      {                  
        PORTD|=0x80;                //shift out DRX data
      }
      else{
        PORTD&=0x7F;
      }
      yDRX<<=1;
    }
    else
    {
      yDTX<<=1;                    //get DTX data and shift it in
      yDTX|= PINB & 0x01;          //DTX connected to Arduino.D8 = PORTB0
      if(yCycleCtr==18)
      {                  
        bitClear(TIMSK2,OCIE2A);
        TIMSK0|=1;                  //Enable timer0 again, so that standard Arduino timing functions work again.
        bDoneFlag=true;
      }
    }    
  }
}


